﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LanhuFx.Services.Model;
using LanhuFx.Services.Model.Dto;
using LanhuFx.Services.Model.View;
using LanhuFx.Context.PgSql.ResourcesModels;
using LanhuFx.Identity;

namespace LanhuFx.Services
{
    public class IdentityService
    {
        private readonly LanhuFxContext _Context;
        private readonly IdentitySetting _Setting;
        private readonly Identity_DESHelper _DESHelper;
        private readonly Md5Service _md5;
        private readonly WebSetSettingServices _config;
        private readonly IMapper _mapper;
        private readonly TokenService _tokenService;
        private readonly PermissionService _permissionService;

        public IdentityService(LanhuFxContext arg_Context
            , IdentitySetting arg_Setting
            , Identity_DESHelper arg_DESHelper
            , Md5Service arg_Md5Service
            , WebSetSettingServices arg_config
            , TokenService arg_tokenService
            , IMapper arg_mapper
            , PermissionService arg_permissionService)
        {
            this._Context = arg_Context;
            this._Setting = arg_Setting;
            this._DESHelper = arg_DESHelper;
            this._md5 = arg_Md5Service;
            this._config = arg_config;
            this._mapper = arg_mapper;
            this._permissionService = arg_permissionService;
            this._tokenService = arg_tokenService;
        }

        public string Decrypt(Dto_Decrypt arg)
        {
            return this._DESHelper.Decrypt(arg.value);
        }
        
        ///// <summary>
        ///// 发送短信验证码
        ///// </summary>
        ///// <param name="arg"></param>
        ///// <returns></returns>
        //public async Task<string> SendSmsAsync(DtoSendSms arg)
        //{
        //    string img_code_key = string.Format(RedisKeyDictionaries.IDENTITY_NOLOGIN_IMG_CODE
        //        , Guid.Parse(arg.RequestId).ToString("N"));

        //    string img_code = _RedisHelp.Get<string>(img_code_key);

        //    _RedisHelp.Remove(img_code_key);

        //    if (arg.ImgCode != img_code)
        //    {
        //        throw new ResponseException(ResponseStateCdode.error, "验证码错误");
        //    }

        //    string code = new Random().Next(0, 9999).ToString("0000");

        //    _RedisHelp.Insert<string>(string.Format(RedisKeyDictionaries.IDENTITY_NOLOGIN_SMS_CODE
        //        , arg.MobilePhone), code, 300);

        //    await _publisher.PublishAsync(
        //        name: CapDictionaries.EXTERNALPUSH_SMS_REGISTRATION
        //        , contentObj: new Dto_ExternalPushSmsRegistration()
        //        {
        //            Code = code,
        //            MobilePhone = arg.MobilePhone
        //        }
        //        , callbackName: CapDictionaries.EXTERNALPUSH_SMS_REGISTRATION_CALLBACK);

        //    return "验证通过";
        //}

        /// <summary>
        /// 用户登陆
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public ViewLogin Login(DtoLogin arg)
        {
            Console.WriteLine("开始登录逻辑");
            //LoginValid(arg);
            if (arg.AccountType == "历史设备记录")
            {
                throw new ResponseException(ResponseStateCdode.error, "暂未实现此功能");
            }
            else if (_Setting.CheckPasswordType.Contains(arg.AccountType))
            {
                var account = _Context.IdentityAccount
                    .IgnoreQueryFilters()
                    .Where(o => o.Account == arg.UserName && o.Accounttype == arg.AccountType)
                    .Include(o => o.User)
                    .FirstOrDefault();

                if (account == null)
                    throw new ResponseException(ResponseStateCdode.error, "用户名或密码不正确");

                string be_password = _md5.GetMD5(_DESHelper.Encrypt(arg.Password));

                if (account == null || account.Password != be_password)
                    throw new ResponseException(ResponseStateCdode.error, "用户名或密码不正确");

                if (account.Userid == null || account.User == null)
                    throw new ResponseException(ResponseStateCdode.error, "该账号未绑定员工");

                string[] checkState = new string[] { "正常", "正式", "实习" };

                if (!string.IsNullOrEmpty(account.User.Userstate) && !checkState.Contains(account.User.Userstate))
                {
                    throw new ResponseException(ResponseStateCdode.error, $"该用户已{account.User.Userstate}");
                }

                List<UserTenant> userTenant = GetUserTenant(account.User.Id);

                UserToken token = new UserToken()
                {
                    Token = Guid.NewGuid(),
                    Tenant = userTenant,
                    UserName = account.User.Username,
                    TeamId = account.User.Teamid,
                    UserId = account.Userid
                };

                return new ViewLogin()
                {
                    Token = _DESHelper.Encrypt(JsonConvert.SerializeObject(token)),
                    TeamId = token.TeamId,
                    Tenants = userTenant,
                };
            }
            else
            {
                throw new ResponseException(ResponseStateCdode.error, "未识别的账号类型");
            }
        }

        ///// <summary>
        ///// 切换团队
        ///// </summary>
        ///// <param name="arg_token"></param>
        ///// <param name="arg_session"></param>
        ///// <param name="arg_tenant"></param>
        ///// <returns></returns>
        //public ViewLogin ChangTenant(UserToken arg_token, DtoChangTenant arg_tenant)
        //{
        //    List<UserTenant> userTenant = GetUserTenant(arg_session.UserId.Value, false);

        //    if (userTenant == null || userTenant.Count <= 0)
        //    {
        //        throw new ResponseException(ResponseStateCdode.error, "无此团队操作权限，切换团队失败");
        //    }

        //    if (!userTenant.Where(o => o.Id == arg_tenant.TeamId).Any())
        //    {
        //        throw new ResponseException(ResponseStateCdode.error, "无此团队操作权限，切换团队失败");
        //    }

        //    arg_session.TeamId = arg_tenant.TeamId;

        //    SaveIdentityLoginLog(arg_session, true);

        //    _RedisHelp.Insert<UserSession>(string.Format(RedisKeyDictionaries.IDENTITY_TOKEN, arg_token.Token.ToString("N"))
        //            , arg_session, _config.WebSetSetting.TermValidity);

        //    return new ViewLogin()
        //    {
        //        TerminalId = arg_session.TerminalId,
        //        TeamId = arg_session.TeamId,
        //        Tenants = userTenant
        //    };
        //}

        /// <summary>
        /// 用户注册
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public View_UserInfo Registration(DtoRegistration arg, bool IsChcekSmsCode)
        {
            if (_Setting.CheckPasswordType.Contains(arg.AccountType))
            {
                //if (!CheckSmsCode(new DtoCheckSmsCode()
                //{
                //    SmsCode = arg.SmsCode,
                //    AccountType = arg.AccountType,
                //    UserName = arg.UserName
                //}, true) && IsChcekSmsCode)
                //{
                //    throw new ResponseException(ResponseStateCdode.error, "短信验证码错误");
                //}

                if (_Context.IdentityAccount.Where(o => o.Account == arg.UserName && o.Accounttype == arg.AccountType).Any())
                {
                    throw new ResponseException(ResponseStateCdode.error, "账号已存在");
                }
                //用户信息校验
                // RegisterInfoValid(arg);

                IdentityUserinfo info = new IdentityUserinfo()
                {
                    Createdat = DateTime.Now,
                    Id = Guid.NewGuid(),
                    Sysidentity = "普通用户",
                    Userstate = "正常",
                    Username = arg.FullName
                };

                if (info.IdentityUsertenant == null)
                    info.IdentityUsertenant = new List<IdentityUsertenant>();

                IdentityTenant tenant = null;

                if (!string.IsNullOrEmpty(arg.TeamId))
                {
                    Guid g_TeamId = new Guid();
                    if (Guid.TryParse(arg.TeamId, out g_TeamId))
                    {
                        tenant = _Context.IdentityTenant.Where(o => o.Teamid == g_TeamId).FirstOrDefault();
                    }

                    if (tenant == null)
                    {
                        throw new ResponseException(ResponseStateCdode.error, "团队不存在");
                    }

                    info.IdentityUsertenant.Add(new IdentityUsertenant()
                    {
                        Teamid = tenant.Teamid,
                        Userid = info.Id
                    });
                }

                if (info.IdentityAccount == null)
                    info.IdentityAccount = new List<IdentityAccount>();

                info.IdentityAccount.Add(new IdentityAccount()
                {
                    Account = arg.UserName,
                    Accounttype = arg.AccountType,
                    Createdat = DateTime.Now,
                    Id = Guid.NewGuid(),
                    Password = _md5.GetMD5(_DESHelper.Encrypt(arg.Password)),
                    Tokenid = null,
                    Userid = info.Id,
                    Teamid = tenant.Teamid
                });

                _Context.IdentityUserinfo.Add(info);

                _Context.SaveChanges();

                return _mapper.Map<View_UserInfo>(info);
            }
            throw new ResponseException(ResponseStateCdode.error, "未识别的账号类型");
        }

        ///// <summary>
        ///// 验证短信验证码是否正确
        ///// </summary>
        ///// <param name="arg"></param>
        ///// <param name="isDelCode">是否删除验证码</param>
        ///// <returns></returns>
        //public bool CheckSmsCode(DtoCheckSmsCode arg, bool isDelCode)
        //{
        //    if (arg.AccountType == "手机号")
        //    {
        //        string key = string.Format(RedisKeyDictionaries.IDENTITY_NOLOGIN_SMS_CODE
        //            , arg.UserName);

        //        var code = _RedisHelp.Get<string>(key);

        //        if (isDelCode)
        //        {
        //            _RedisHelp.Remove(key);
        //        }

        //        //9999为测试功能用验证码
        //        if (code != arg.SmsCode && arg.SmsCode != "9999")
        //        {
        //            throw new ResponseException(ResponseStateCdode.error, "短信验证码错误");
        //        }
        //    }
        //    return true;
        //}

        /// <summary>
        /// 检查团队是否存在
        /// 未登陆状态时，返回true：团队存在
        /// 已登陆状态时，返回true：未加入团队，false：已加入团队
        /// </summary>
        /// <param name="arg_Tenant"></param>
        /// <param name="arg_session">如果未null则不检查团队于当前登陆用户关系</param>
        public ViewCheckTenant CheckTenant(string arg_Tenant, UserToken arg_token)
        {
            IdentityTenant tenant = null;

            if (!string.IsNullOrEmpty(arg_Tenant))
            {
                Guid g_TeamId = new Guid();
                if (Guid.TryParse(arg_Tenant, out g_TeamId))
                {
                    tenant = _Context.IdentityTenant.Where(o => o.Teamid == g_TeamId).FirstOrDefault();
                }
            }

            if (tenant == null)
            {
                throw new ResponseException(ResponseStateCdode.error, "团队不存在");
            }

            if (arg_token != null)
            {
                var usertenant = GetUserTenant(arg_token.UserId.Value);

                return new ViewCheckTenant()
                {
                    CheckTenant = usertenant.Where(o => o.Id == tenant.Teamid).Any() == false,
                    IsLogin = true,
                };
            }

            return new ViewCheckTenant()
            {
                CheckTenant = true,
                IsLogin = true,
            };
        }

        /// <summary>
        /// 获取当前用户所在团队
        /// </summary>
        /// <param name="arg_session"></param>
        /// <returns></returns>
        public List<UserTenant> ListUserTenant(UserToken arg_token)
        {
            return GetUserTenant(arg_token.UserId.Value);
        }
        
        ///// <summary>
        ///// 图形验证码存入缓存
        ///// </summary>
        ///// <param name="arg"></param>
        //public void SaveSmsImgCode(Dto_SmsImgCode arg)
        //{
        //    this._RedisHelp.Insert<string>(string.Format(RedisKeyDictionaries.IDENTITY_NOLOGIN_IMG_CODE, arg.RequestId.ToString("N"))
        //        , arg.Code);
        //}

        /// <summary>
        /// 加入团队
        /// </summary>
        /// <param name="arg"></param>
        public void AddTenant(DtoAddTenant arg, UserToken arg_token)
        {
            var check = CheckTenant(arg.TeamId, arg_token);

            if (!check.IsLogin)
            {
                throw new ResponseException(ResponseStateCdode.error, "登录信息异常");
            }

            if (check.CheckTenant)
            {
                _Context.IdentityUsertenant.Add(new IdentityUsertenant()
                {
                    Teamid = Guid.Parse(arg.TeamId),
                    Userid = arg_token.UserId.Value
                });

                _Context.SaveChanges();
            }

            throw new ResponseException(ResponseStateCdode.error, "已经加入该团队");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public bool AddUserAccount(Dto_AddUserAccount arg)
        {
            var person = _Context.IdentityUserinfo.Include(c => c.IdentityUserrole)
                .Where(c => c.Id == arg.CloneFromPersonId && c.Teamid == arg.UserSession.TeamId)
                .IgnoreQueryFilters()
                .FirstOrDefault();
            IdentityUserinfo info = new IdentityUserinfo()
            {
                Createdat = DateTime.Now,
                Id = arg.UserSession.UserId.Value,
                Sysidentity = "普通用户",
                Userstate = "正常",
                Username = arg.FullName
            };

            if (info.IdentityUsertenant == null)
                info.IdentityUsertenant = new List<IdentityUsertenant>();

            IdentityTenant tenant = null;

            if (arg.UserSession.TeamId != null)
            {

                tenant = _Context.IdentityTenant.Where(o => o.Teamid == arg.UserSession.TeamId).IgnoreQueryFilters().FirstOrDefault();

                if (tenant == null)
                {
                    throw new ResponseException(ResponseStateCdode.error, "团队不存在");
                }

                info.IdentityUsertenant.Add(new IdentityUsertenant()
                {
                    Teamid = tenant.Teamid,
                    Userid = info.Id
                });
            }

            if (info.IdentityAccount == null)
                info.IdentityAccount = new List<IdentityAccount>();

            info.IdentityAccount.Add(new IdentityAccount()
            {
                Account = $"{tenant.Tenantcode}-{arg.Account}",
                Accounttype = "用户名",
                Createdat = DateTime.Now,
                Id = Guid.NewGuid(),
                Password = _md5.GetMD5(_DESHelper.Encrypt(string.IsNullOrEmpty(arg.Password) ? "123456" : arg.Password)),
                Tokenid = null,
                Userid = info.Id,
                Teamid = arg.UserSession.TeamId
            });
            foreach (var item in person.IdentityUserrole)
            {
                info.IdentityUserrole.Add(new IdentityUserRole
                {
                    Roleid = item.Roleid,
                    Userid = info.Id,
                    Teamid = arg.UserSession.TeamId
                });
            }
            _Context.IdentityUserinfo.Add(info);

            _Context.SaveChanges();
            return true;
        }

        #region 内部调用

        /// <summary>
        /// 保存登陆记录
        /// </summary>
        /// <param name="arg_session"></param>
        /// <param name="arg_isSaveChanges"></param>
        private void SaveIdentityLoginLog(UserToken arg_token, bool arg_isSaveChanges)
        {
            _Context.IdentityLoginlog.Add(new IdentityLoginlog()
            {
                //Accountid = arg_token.AccountId,
                Createdat = DateTime.Now,
                //Deviceinfo = arg_token.Device,
                Id = Guid.NewGuid(),
                Teamid = arg_token.TeamId,
                //Terminalid = arg_token.TerminalId,
                Userid = arg_token.UserId
            });

            if (arg_isSaveChanges)
                _Context.SaveChanges();
        }

        private List<UserTenant> GetUserTenant(Guid arg_UserId)
        {
            List<UserTenant> data = null;

            //string key = string.Format(RedisKeyDictionaries.IDENTITY_USERTENANT, arg_UserId.ToString("N"));

            //if (arg_isReadCache)
            //    data = _RedisHelp.Get<List<UserTenant>>(key);

            if (data == null)
                data = new List<UserTenant>();

            if (data.Count <= 0)
            {
                var db_list = _Context.IdentityUsertenant.IgnoreQueryFilters().Where(o => o.Userid == arg_UserId).Include(o => o.Team).ToList();

                if (db_list != null && db_list.Count > 0)
                {
                    db_list.ForEach(o =>
                    {
                        data.Add(new UserTenant()
                        {
                            Id = o.Team.Teamid,
                            Name = o.Team.Tenantname
                        });
                    });

                    //_RedisHelp.Insert<List<UserTenant>>(key, data, _config.WebSetSetting.TermValidity);
                }
            }

            return data;
        }


        #endregion

        /// <summary>
        /// 用户修改密码
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public string ChangePassward(Dto_ChangePassward password)
        {
            
            var rs = _Context.IdentityAccount.Where(c => 
                c.Userid == _tokenService.GetToken().UserId
            );
            if (rs.Any())
            {
                var result = rs.FirstOrDefault();

                var newPassword = _md5.GetMD5(_DESHelper.Encrypt(password.password));
                result.Password = newPassword;
                _Context.SaveChanges();
                return "密码修改成功";
            }
            else
            {
                throw new ResponseException(ResponseStateCdode.error, $"用户不存在");
            }
        }

        public dynamic GetAccount(Guid arg_userId)
        {
            var TeamId = _tokenService.GetToken().TeamId;
            var TenantCode = _Context.IdentityTenant.Where(c => c.Teamid == TeamId).Select(o => o.Tenantcode).FirstOrDefault();

            if (!_Context.IdentityUserinfo.Where(o => o.Id == arg_userId).Any())
            {
                _Context.IdentityUserinfo.Add(new IdentityUserinfo()
                {
                    Id = arg_userId,
                    Userstate = "正常",
                    Sysidentity = "普通用户",
                    Createdat = DateTime.Now,
                    Teamid = TeamId
                });

                _Context.SaveChanges();
            }

            var result = _Context.IdentityAccount.Where(c =>
                c.Userid != null
                && c.Userid.Value == arg_userId
                && c.Accounttype == "用户名").FirstOrDefault();

            string account = "";

            if (result != null && !string.IsNullOrEmpty(result.Account))
            {
                if (result.Account.IndexOf(string.Format("{0}-", TenantCode)) == 0)
                {
                    account = result.Account.Substring(TenantCode.Length + 1);
                }
                else
                {
                    account = result.Account;
                }
            }

            return new
            {
                TenantCode = TenantCode,
                Account = account
            };
        }

        /// <summary>
        /// 第三方修改密码
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public string OtherChangePassword(DtoChangePassword dto)
        {
            var token = _tokenService.GetToken();
            var TeamId = token.TeamId;
            var TenantCode = _Context.IdentityTenant.Where(c => c.Teamid == TeamId).Select(o => o.Tenantcode).FirstOrDefault();

            if (!_Context.IdentityUserinfo.Where(o => o.Id == dto.UserId).Any())
            {
                throw new ResponseException(ResponseStateCdode.error, "UserId不存在");
            }

            var result_exists = _Context.IdentityAccount.Where(c =>
                c.Userid != null
                && c.Userid.Value != dto.UserId
                && c.Account == string.Format("{0}-{1}", TenantCode, dto.Account)
                && c.Accounttype == "用户名");

            if (result_exists.Any())
            {
                throw new ResponseException(ResponseStateCdode.error, string.Format("账号：{0}-{1}已经存在", TenantCode, dto.Account));
            }

            var result = _Context.IdentityAccount.Where(c =>
                c.Userid != null
                && c.Userid.Value == dto.UserId
                && c.Accounttype == "用户名");

            var newPassword = _md5.GetMD5(_DESHelper.Encrypt(dto.Password));

            if (result.Any())
            {
                var item = result.FirstOrDefault();

                item.Account = string.Format("{0}-{1}", TenantCode, dto.Account);
                item.Password = newPassword;
            }
            else
            {
                _Context.IdentityAccount.Add(new IdentityAccount()
                {
                    Account = string.Format("{0}-{1}", TenantCode, dto.Account),
                    Accounttype = "用户名",
                    Createdat = DateTime.Now,
                    Id = Guid.NewGuid(),
                    Password = newPassword,
                    Teamid = TeamId,
                    Tokenid = null,
                    Userid = dto.UserId
                });
            }

            if (!_Context.IdentityUsertenant.Where(o => o.Userid == dto.UserId && o.Teamid == TeamId).Any())
            {
                _Context.IdentityUsertenant.Add(new IdentityUsertenant()
                {
                    Teamid = TeamId.Value,
                    Userid = dto.UserId
                });
            }

            _Context.SaveChanges();
            return "密码修改成功";
        }

    }
}
